from typing import Any

from aiogram import Bot, types
from aiogram_dialog import Dialog, DialogManager, Window
from aiogram_dialog.widgets.kbd import Back, Button, Cancel, Next
from apscheduler.schedulers.asyncio import AsyncIOScheduler
from pydantic import ValidationError
from sqlalchemy.exc import DBAPIError

from app.bot.dialog.dialog_states import BuyVPNSG, VPNRouterSG
from app.bot.dialog.getters.orders import vpn_summary_getter
from app.bot.dialog.widgets import LocaleText
from app.bot.handlers.client.orders.orders_history import user_orders
from app.bot.schemas.order import OrderModel
from app.bot.services.broadcaster import broadcast
from app.bot.services.date_time import get_date_time
from app.bot.services.helpers import get_expiring_on
from app.bot.services.locale import Locale
from app.bot.services.loggers import logger
from app.bot.services.scheduler import jobs
from app.config import Settings
from app.database.services.categories import get_category_by_name
from app.database.services.orders.common import create_order
from app.database.services.stats import update_stats
from app.database.services.users import get_user
from app.database.services.vpn_servers import get_free_vpn_server


async def add_order(call: types.CallbackQuery, widget: Any, manager: DialogManager):
    db_session = manager.middleware_data.get("db_session")
    scheduler: AsyncIOScheduler = manager.middleware_data.get("scheduler")
    locale: Locale = manager.middleware_data.get("locale")
    bot: Bot = manager.middleware_data.get("bot")
    config: Settings = manager.middleware_data.get("config")

    vpn_summ: float = manager.dialog_data.get("vpn_summ")

    user_id: int = call.from_user.id
    user = await get_user(db_session, user_id)

    if widget.widget_id == "vpn_order":
        free_servers = await get_free_vpn_server(db_session, user)
        if len(free_servers) == 0:
            await call.answer(locale.get("no-free-vpn-servers"))
            return

    if user.balance < vpn_summ:
        await call.answer(locale.get("not-enough-balance", balance=user.balance))
        return

    try:
        if widget.widget_id == "vpn_order":
            period = "one_month"
            date_now = get_date_time(get_datetime=True)
            expiring_on = await get_expiring_on(date_now, period)
            category = await get_category_by_name(db_session, "VPN")
            type = "vpn"
        else:
            period = "unlimited"
            expiring_on = None
            category = await get_category_by_name(db_session, "VPN Router")
            type = "vpn_router"

        order = OrderModel(
            type=type,
            user_id=user_id,
            proxies=[],
            summ=vpn_summ,
            period=period,
            category_id=category.id,
            expiring_on=expiring_on,
        )

        order = await create_order(db_session, **order.dict())

        if widget.widget_id == "vpn_order":
            order.vpn_server = free_servers[0]
            scheduler.add_job(
                jobs.generate_vpn_config_job,
                args=(
                    bot,
                    free_servers[0],
                    locale,
                    user_id,
                    order.id,
                    config,
                ),
            )
            logger.info(f"Добавлена задача на настройку впна для юзера {user_id}")
            await call.message.answer(locale.get("vpn-setup"))
        await call.message.answer(locale.get("order-success"))
        await update_stats(db_session, vpns=1)
        await db_session.commit()
        logger.info(f"Добавлен новый заказ на впн {order.id}")

        if widget.widget_id == "vpn_order":
            await manager.switch_to(BuyVPNSG.order_created)
        else:
            await manager.switch_to(VPNRouterSG.order_created)

    except (DBAPIError, ValidationError, Exception) as e:
        logger.exception(e)
        await call.answer(locale.get("error-msg"))
        await broadcast(
            bot,
            [config.tg_bot.developer_id],
            f"Ошибка во время создания заказа {str(e)}",
        )


vpn_info_window = Window(
    LocaleText("vpn-info"),
    Next(
        LocaleText("buy-vpn"),
        id="buy_vpn_button",
    ),
    Cancel(LocaleText("back-btn")),
    state=BuyVPNSG.show_info,
)


create_order_window = Window(
    LocaleText("order-overview"),
    LocaleText("service_type", service_name="{service_name}"),
    LocaleText("selected-period", period="{period}"),
    LocaleText("order-summ", order_summ="{vpn_summ}$"),
    Button(
        LocaleText("confirm-btn"),
        id="vpn_order",
        on_click=add_order,
    ),
    Back(LocaleText("back-btn")),
    Cancel(LocaleText("cancel-btn")),
    state=BuyVPNSG.create_order,
    getter=vpn_summary_getter,
)

order_created_window = Window(
    LocaleText("order-created"),
    Button(LocaleText("my-vpns"), id="vpn", on_click=user_orders),
    Cancel(LocaleText("main-menu-btn")),
    state=BuyVPNSG.order_created,
)

buy_vpn_dialog = Dialog(vpn_info_window, create_order_window, order_created_window)
